﻿using Dispatcher.Core.Providers;
using Dispatcher.Data.Entities.MySql;
using MiniFox.Components;
using MiniFox.Data.EntityFramework;
using MiniFox.Infrastructure;
using MiniFox.Platform.File.Models;
using MiniFox.Platform.File.Providers;
using File = Dispatcher.Data.Entities.MySql.File;

namespace Dispatcher.Data
{
    [AutoResolve]
    public class AttachmentProvider : EntityDataProvider<DispatcherContext>, IAttachmentProvider
    {
        public FileData GetFile(string fileId)
        {
            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.FileId == fileId);
            if (file == null) return null;
            return new()
            {
                FileId = fileId,
                FileName = file.FileName,
                Path = file.Path,
                ContentType = file.MimeType,
                Group = file.Group,
                CreateTime = file.CreateTime,
                UpdateTime = file.UpdateTime
            };
        }

        public FileData GetFile(string group, string path, string fileName)
        {
            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.Group == group && f.Path == path && f.FileName == fileName);
            if (file == null) return null;
            return new()
            {
                FileId = file.FileId,
                FileName = file.FileName,
                Path = file.Path,
                ContentType = file.MimeType,
                Group = file.Group,
                CreateTime = file.CreateTime,
                UpdateTime = file.UpdateTime
            };
        }

        public ResultObject<IEnumerable<FileData>> Query(PagedQueryObject<FileQuery> queryObject)
        {
            var query = this.PagedQueryExecute<Data.Entities.MySql.File>(queryObject);
            return query.GetResultObject(f => new FileData
            {
                FileId = f.FileId,
                FileName = f.FileName,
                Path = f.Path,
                ContentType = f.MimeType,
                Group = f.Group,
                CreateTime = f.CreateTime,
                UpdateTime = f.UpdateTime
            });
        }

        public FileData[] Query(string group, string path, int? top)
        {
            var fileDatas = (from f in this.CurrentDbContext.File
                             where f.Group == @group && (f.Path == path || f.Path.StartsWith($"{path}/"))
                             select new FileData
                             {
                                 FileId = f.FileId,
                                 FileName = f.FileName,
                                 Path = f.Path,
                                 ContentType = f.MimeType,
                                 Group = f.Group,
                                 CreateTime = f.CreateTime,
                                 UpdateTime = f.UpdateTime
                             });
            return fileDatas.ToArray();
        }

        public bool Accept(FileData fileData)
        {
            return Save(fileData);
        }

        public FileData LoadPreSave(string fileId)
        {
            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.FileId == fileId && f.Accepted == false);
            if (file == null) return null;
            return new FileData
            {
                FileId = fileId,
                FileName = file.FileName,
                Path = file.Path,
                ContentType = file.MimeType,
                Group = file.Group,
                CreateTime = file.CreateTime,
                UpdateTime = file.UpdateTime
            };
        }

        public bool PreSave(FileData[] fileDatas)
        {
            List<BatchOperationItem> list = new List<BatchOperationItem>();
            Parallel.ForEach(fileDatas, fileData =>
            {
                var file = new Entities.MySql.File
                {
                    FileId = fileData.FileId,
                    FileName = fileData.FileName,
                    ExtName = fileData.ExtensionName,
                    MimeType = fileData.ContentType,
                    ContentLength = fileData.ContentLength,
                    Group = fileData.Group,
                    Path = fileData.Path,
                    CreateTime = fileData.CreateTime,
                    UpdateTime = fileData.UpdateTime,
                    Accepted = false
                };
                list.Add(new BatchOperationItem
                {
                    Entity = file,
                    State = Microsoft.EntityFrameworkCore.EntityState.Added
                });
            });
            var len = fileDatas.Length;
            return this.CommitBatch(list) >= len;
        }

        public bool Remove(string fileId)
        {
            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.FileId == fileId);

            return this.Delete(file) > 0;
        }

        public bool Rename(string group, string fileId, string newName)
        {
            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.Group == group && f.FileId == fileId);
            file.FileName = newName;
            file.UpdateTime = DateTime.Now;
            return this.Update(file) > 0;
        }

        public bool Save(FileData fileData)
        {
            if (fileData == null) return false;

            var file = this.CurrentDbContext.File.SingleOrDefault(f => f.FileId == fileData.FileId);
            if (file == null)
            {
                file = new()
                {
                    FileId = fileData.FileId,
                    FileName = fileData.FileName,
                    ExtName = fileData.ExtensionName,
                    MimeType = fileData.ContentType,
                    ContentLength = fileData.ContentLength,
                    Group = fileData.Group,
                    Path = fileData.Path,
                    CreateTime = fileData.CreateTime,
                    UpdateTime = fileData.UpdateTime,
                    Accepted = true
                };
                return this.Insert(file) > 0;
            }
            else
            {
                file.UpdateTime = fileData.UpdateTime;
                file.Accepted = true;
                return this.Update(file) > 0;
            }
        }

        public void SetAttachment(string messageId, IEnumerable<FileData> fileDatas)
        {
            if (fileDatas == null || fileDatas.Count() <= 0)
                return;
            List<BatchOperationItem> items = [];
            Parallel.ForEach(fileDatas, fileData =>
            {
                var file = this.CurrentDbContext.File.SingleOrDefault(f => f.FileId == fileData.FileId);
                file.UpdateTime = DateTime.Now;
                file.Accepted = true;
                items.Add(new ()
                {
                    Entity = file,
                    State = Microsoft.EntityFrameworkCore.EntityState.Modified
                });
                items.Add(new ()
                {
                    Entity = new MessageAttachment
                    {
                        MessageId = messageId,
                        FileId = file.FileId
                    },
                    State = Microsoft.EntityFrameworkCore.EntityState.Added
                });
            });
            this.CommitBatch(items);
        }

        public ResultObject<IEnumerable<FileData>> Query(string group, PagedQueryObject<FileQuery> queryObject)
        {
            throw new NotImplementedException();
        }
    }
}
